﻿<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>动态跟踪</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="SECT1">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="monitoring-locks.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="monitoring.html">快退</a></td><td width="60%" align="center" valign="bottom">章25. 监控数据库的活动</td><td width="10%" align="right" valign="top"><a href="monitoring.html">快进</a></td><td width="10%" align="right" valign="top"><a href="diskusage.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<div class="SECT1"><h1 class="SECT1"><a name="DYNAMIC-TRACE">25.4. 动态跟踪</a></h1><a name="AEN25969"></a>
<p>PostgreSQL 允许对数据库服务器进行动态跟踪。这样就允许在代码内特定的点上调用外部工具来跟踪执行过程。目前此功能主要目的是为了提供给数据库开发者使用，它要求使用者对代码非常熟悉。</p>
<p>许多跟踪点(也被称为"探头")已经插入在源代码中了，不过缺省为禁用状态，用户必须在编译前运行 configure 脚本时明确启用它们。</p>
<p>目前仅支持 Solaris Express 和 Solaris 10+ 系统上的 DTrace 工具。预计将来 DTrace 将会移植到 FreeBSD 和 Mac OS X 上。理论上也可以通过更改 <tt class="FILENAME">src/include/pg_trace.h</tt> 中的 <tt class="LITERAL">PG_TRACE</tt> 宏来支持其它跟踪工具。</p>
<div class="SECT2"><h2 class="SECT2"><a name="COMPILING-FOR-TRACE">25.4.1. 编译动态跟踪支持</a></h2>
<p>跟踪点是默认禁止的，你必须在运行 configure 脚本时明确使用 <tt class="OPTION">--enable-dtrace</tt> 选项来启用 DTrace 支持。参见<a href="install-procedure.html">节14.5</a>获取更多信息。</p>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="TRACE-POINTS">25.4.2. 内置跟踪点</a></h2>
<p><a href="dynamic-trace.html#TRACE-POINT-TABLE">表25-3</a>显示的是在源代码中提供的标准跟踪点，此外，也可以根据特定的具体问题添加其它跟踪点。</p>
<div class="TABLE"><a name="TRACE-POINT-TABLE"></a>
<p><b>表25-3. 内置跟踪点</b></p>
<table border="1" class="CALSTABLE"><col><col><col>
<thead>
<tr><th>名字</th><th>参数</th><th>概述</th></tr>
</thead>
<tbody>
<tr><td>transaction__start</td><td>(int transactionId)</td><td>开始新事务</td></tr>
<tr><td>transaction__commit</td><td>(int transactionId)</td><td>事务成功完成</td></tr>
<tr><td>transaction__abort</td><td>(int transactionId)</td><td>事务失败</td></tr>
<tr><td>lwlock__acquire</td><td>(int lockid, int mode)</td><td>成功获取 LWLock</td></tr>
<tr><td>lwlock__release</td><td>(int lockid, int mode)</td><td>成功释放 LWLock</td></tr>
<tr><td>lwlock__startwait</td><td>(int lockid, int mode)</td><td>未立即获得 LWLock 并且后端开始等待该锁</td></tr>
<tr><td>lwlock__endwait</td><td>(int lockid, int mode)</td><td>后端已释放等待的 LWLock </td></tr>
<tr><td>lwlock__condacquire</td><td>(int lockid, int mode)</td><td>成功获得调用者指定不必等待的 LWLock</td></tr>
<tr><td>lwlock__condacquire__fail</td><td>(int lockid, int mode)</td><td>未能获得调用者指定不必等待的 LWLock</td></tr>
<tr><td>lock__startwait</td><td>(int locktag_field2, int lockmode)</td><td>由于不能立即获取超重锁(lmgr lock)而进入等待</td></tr>
<tr><td>lock__endwait</td><td>(int locktag_field2, int lockmode)</td><td>等待获取超重锁(lmgr lock)完毕(也就是成功获取)</td></tr>
</tbody>
</table>
</div>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="USING-TRACE-POINTS">25.4.3. 使用跟踪点</a></h2>
<p>下面的例子示范了一个分析事务次数的 DTrace 脚本，可以用来代替在性能测试之前和之后的 <tt class="STRUCTNAME">pg_stat_database</tt> 快照。</p>
<pre class="PROGRAMLISTING">#!/usr/sbin/dtrace -qs

postgresql$1:::transaction-start
{
      @start["Start"] = count();
      self-&#62;ts  = timestamp;
}

postgresql$1:::transaction-abort
{
      @abort["Abort"] = count();
}

postgresql$1:::transaction-commit
/self-&#62;ts/
{
      @commit["Commit"] = count();
      @time["Total time (ns)"] = sum(timestamp - self-&#62;ts);
      self-&#62;ts=0;
}</pre>
<p>请注意在使用 D 脚本时，跟踪点名字中的双下划线是如何被连字符取代的。执行完毕后，示范 D 脚本的输出如下：</p>
<pre class="SCREEN"># ./txn_count.d `pgrep -n postgres`
^C

Start                                          71
Commit                                         70
Total time (ns)                        2312105013</pre>
<p>必须在实际使用跟踪程序前进行仔细的编写和充分的调试，否则收集到的跟踪信息可能毫无意义。大多数问题是由于外部跟踪程序错误导致的而不是底层系统。在讨论使用动态跟踪发现的信息时，应确保在其中包含你使用的跟踪脚本。</p>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="DEFINING-TRACE-POINTS">25.4.4. 定义跟踪点</a></h2>
<p>开发者可以在代码中任意位置定义新的跟踪点，当然这要重新编译之后才能生效。</p>
<p>可以使用一个跟踪宏来插入跟踪点。可以根据将在该跟踪点上检查多少变量来选择宏。使用跟踪点的名字就可以仅在一行代码上跟踪某个事件的发生，例如：</p>
<pre class="PROGRAMLISTING">PG_TRACE (my__new__trace__point);</pre>
<p>通过使用与跟踪点名字后面的参数个数一样多的 <tt class="LITERAL">PG_TRACE</tt><tt class="REPLACEABLE"><i>n</i></tt> 宏，使用动态跟踪工具检查一个或多个变量，就可以提供更复杂的跟踪点：</p>
<pre class="PROGRAMLISTING">PG_TRACE3 (my__complex__event, varX, varY, varZ);</pre>
<p>transaction__start 跟踪点的定义如下：</p>
<pre class="PROGRAMLISTING">static void
StartTransaction(void)
{
    ...

    /*
     * 生成一个新的事务 id
     */
    s-&#62;transactionId = GetNewTransactionId(false);

    XactLockTableInsert(s-&#62;transactionId);

    PG_TRACE1(transaction__start, s-&#62;transactionId);

    ...
}    </pre>
<p>请注意动态跟踪工具是如何获得事务 ID 的。</p>
<p>动态跟踪工具可能需要定义更多的跟踪点。例如，DTrace 要求在 <tt class="FILENAME">src/backend/utils/probes.d</tt> 文件中添加新的跟踪点，如下所示：</p>
<pre class="PROGRAMLISTING">provider postgresql {
      ...
      probe transaction__start(int);
      ...
 };</pre>
<p>必须注意要将"探头"参数的数据类型与 <tt class="LITERAL">PG_TRACE</tt> 宏使用的数据类型相匹配。编译时并不对此进行检查。你可以通过重新编译来检查新增的跟踪点是否可用，然后以 root 运行新的二进制文件，执行类似下述 DTrace 命令：</p>
<pre class="PROGRAMLISTING">dtrace -l -n transaction-start</pre>
</div>
</div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="monitoring-locks.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="diskusage.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">查看锁</td><td width="34%" align="center" valign="top"><a href="monitoring.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">监控磁盘使用情况</td></tr>
</table>
</div>
</body></html>